#ifndef RASTERIZER_H
#define RASTERIZER_H

#include "geometry.h"
#include "mathengine.h"
#include "tgaimage.h"
#include "model.h"
#include "rendercontext.h"

#include <QImage>
#include <vector>
#include <memory>
#include <QSize>

namespace raster {

using mathengine::Vec2f;
using mathengine::Vec3f;
using mathengine::Vec4f;
using mathengine::Matrix44f;

class Model;
struct IShader;

class Rasterizer {
public:
    typedef enum { CounterClockwise, Clockwise } TriangleVertexOrder;

    Rasterizer(int w, int h, QImage &image);
    ~Rasterizer() = default;

    void drawScene();
    void clear(const TGAColor &color);
    void drawTriangle(const mathengine::Vec4f *pts, IShader &shader);
    void drawLine(const Vec2f& p0, const Vec2f& p1, const TGAColor& color);
    const QImage &getColorBuffer() const;
    std::shared_ptr<Model> currentModel();
    RenderContext currentRenderContext();
    Vec3f eyePos();
    Vec3f lightDir();
    void setEyePos(Vec3f pos);
    void setLightDir(Vec3f dir);
    void resize(QSize size);
    void viewport(int x, int y, int w, int h);
    void flipHorizontally();
    void flipVertically();
    void saveAsTGAFile();

private:
    void setPixel(int x, int y, const TGAColor &color);
    QColor shadePixel(const mathengine::Vec3f &normal);

    void clearZBuffer();
    int index(int x, int y) const;

    void updateContext();

    bool backCulling = false;
    TriangleVertexOrder vertexOrder = CounterClockwise;

    QImage &framebuffer_;
    std::vector<float> zbuffer_;
    int width, height;
    std::shared_ptr<Model> model_;
    RenderContext context_;

    Vec3f lightDir_;
    Vec3f eye_;
    Vec3f center_;
    Vec3f up_;
    int depth_;
};

}

#endif
